package com.yanqu.road.server.manger.activity.yingxin;

import com.yanqu.road.entity.activity.yingxin.config.YingXinConfig;
import com.yanqu.road.entity.activity.yingxin.game.YingXinGameData;
import com.yanqu.road.entity.activity.yingxin.game.YingXinLine;
import com.yanqu.road.utils.RandomHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;

public class YingXinGameLogic {

    private static Logger logger = LogManager.getLogger(YingXinGameLogic.class.getName());

    // 写死的数据
    private static final int LONG_BALLS_COUNT = 8; // 长行的球数量
    private static final int SHORT_BALLS_COUNT = 2; // 短行的球数量
    private static final int GAME_OVER_LENGTH = 13; // 游戏结束行数
    public static final int MAX_BALLS_COUNT = 10; // 每行最大的数量
    public static final int SHOW_LENGTH = 9; // 最小显示长度
    public static final int TOTAL_COLOR_COUNT = 4; // 总颜色数
    public static final int INIT_Y = 5; // 初始Y值

    /**
     * 是否游戏结束
     */
    public static boolean isGameOver(YingXinGameData gameData) {
        return gameData.getLines().size() >= GAME_OVER_LENGTH;
    }

    /**
     * 自动补充行数
     */
    public static void autoAddLine(YingXinConfig config, YingXinGameData gameData, RandomHelper randomHelper) {
        List<YingXinLine> lines = gameData.getLines();
        int maxY = gameData.getMaxY();
        int minY = lines.size() > 0 ? lines.get(0).getY() : maxY;
        int addLineCount = lines.size() == 0 ? SHOW_LENGTH : SHOW_LENGTH - (maxY - minY) - 1;
        for (int i = 0; i < addLineCount; i++) {
            addOneLine(config, gameData, randomHelper);
        }
    }

    /**
     * 添加新的一行
     */
    public static void addOneLine(YingXinConfig config, YingXinGameData gameData, RandomHelper randomHelper) {
        YingXinLine line = buildOneLine(config, gameData.getMaxY() + 1, gameData.getCur(), randomHelper);

        List<YingXinLine> lines = gameData.getLines();
        lines.add(line);
        gameData.setMaxY(lines.get(lines.size() - 1).getY());
        gameData.setHead(calHeadColor(line, randomHelper));
    }

    /**
     * 生成新手数据
     */
    public static YingXinGameData buildStartData(RandomHelper randomHelper) {
        List<YingXinLine> lines = new ArrayList<>();
        int y = INIT_Y + 1;
        lines.add(new YingXinLine(y++, new int[]{0, -1, 3, 3, 3, 3, 3, 4, 3, 0}));
        lines.add(new YingXinLine(y++, new int[]{0, 1, 2, 4, 3, 1, 2, 4, 3, 0}));
        lines.add(new YingXinLine(y++, new int[]{4, 3, 0, 0, 0, 0, 0, 0, 0, 0}));
        lines.add(new YingXinLine(y++, new int[]{0, 1, 2, 4, 3, 1, 2, 4, 3, 0}));
        lines.add(new YingXinLine(y++, new int[]{0, 1, 2, 4, 3, 1, 2, 4, 3, 0}));
        lines.add(new YingXinLine(y++, new int[]{0, 0, 0, 0, 0, 0, 0, 0, 4, 3}));
        lines.add(new YingXinLine(y++, new int[]{0, 1, 2, 4, 3, 1, 2, 4, 3, 0}));
        lines.add(new YingXinLine(y++, new int[]{0, 1, 2, 4, 3, 1, 2, 4, 3, 0}));
        lines.add(new YingXinLine(y++, new int[]{4, 3, 0, 0, 0, 0, 0, 0, 0, 0}));

        YingXinGameData gameData = new YingXinGameData();
        gameData.setLines(lines);
        gameData.setCur(3);
        gameData.setHead(calHeadColor(lines.get(lines.size() - 1), randomHelper));
        gameData.setMaxY(lines.get(lines.size() - 1).getY());
        return gameData;
    }

    /**
     * 获取用于生成下一行的颜色参数
     */
    private static int calHeadColor(YingXinLine line, RandomHelper randomHelper) {
        int[] ballArray = line.getBalls();
        if (isBuildFromLeft(line.getY() + 1)) {
            // 下一行顺序生成，需要上一行最左边
            for (int i = 0; i < ballArray.length; i++) {
                if (ballArray[i] != 0) {
                    return ballArray[i];
                }
            }
        } else {
            // 下一行逆序生成，需要上一行最右边
            for (int i = ballArray.length - 1; i > 0; i--) {
                if (ballArray[i] != 0) {
                    return ballArray[i];
                }
            }
        }
        return randomHelper.next(TOTAL_COLOR_COUNT) + 1;
    }

    /**
     * 是否从左往右生成
     */
    private static boolean isBuildFromLeft(int y) {
        return (y + 5) % 6 <= 3;
    }

    /**
     * 获取新的一行
     */
    private static YingXinLine buildOneLine(YingXinConfig config, int y, int headColor, RandomHelper randomHelper) {
        int[] balls = new int[MAX_BALLS_COUNT];
        int count = calBuildBallCount(y);
        int startY = calBuildStartX(y);
        int addNum = isBuildFromLeft(y) ? 1 : -1;
        int lastColor = headColor;
        int sameColorCount = 0;
        int ratioType = isShortLine(y) ? 2 : 1; // 概率公式类型
        // 首个颜色
        balls[startY] = calNextBallColor(config, lastColor, 3, 0, randomHelper);
        lastColor = balls[startY];
        startY += addNum;
        count--;
        // 后续颜色
        for (; count > 0; count--) {
            int tmpColor = calNextBallColor(config, lastColor, ratioType, sameColorCount, randomHelper);
            if (tmpColor == lastColor) {
                sameColorCount++;
            } else {
                sameColorCount = 0;
            }
            balls[startY] = tmpColor;
            lastColor = tmpColor;
            startY += addNum;
        }
        // 返回结果
        YingXinLine line = new YingXinLine();
        line.setY(y);
        line.setBalls(balls);
        return line;
    }

    /**
     * 生成几个
     */
    private static int calBuildBallCount(int y) {
        return y % 3 == 2 ? SHORT_BALLS_COUNT : LONG_BALLS_COUNT;
    }

    /**
     * 起始下标
     */
    private static int calBuildStartX(int y) {
        switch (y % 6) {
            case 0:
                return 8;
            case 1:
            case 3:
            case 4:
                return 1;
            case 2:
                return 0;
            case 5:
                return 9;
            default:
                return 1;
        }
    }

    /**
     * 是否是短的行
     */
    private static boolean isShortLine(int y) {
        return y % 3 == 2;
    }

    /**
     * 计算下一个颜色
     *
     * @param lastColor      上一个的颜色    为宝箱时，随机一个颜色
     * @param ratioType      概率公式        1：长行连续，2：短行连续，3：每行首个
     * @param sameColorCount 已有同颜色数    从0开始
     * @return int 颜色
     */
    private static int calNextBallColor(YingXinConfig config, int lastColor, int ratioType, int sameColorCount, RandomHelper randomHelper) {
        // 如果前一个没颜色，则4个随机
        if (lastColor <= 0) {
            return randomHelper.next(TOTAL_COLOR_COUNT) + 1;
        }
        // 先判断同色
        if (ratioType == 1 && randomHelper.next(1000) < config.getSameColorRatioA() - sameColorCount * config.getSameColorRatioC()
                || ratioType == 2 && randomHelper.next(1000) < config.getSameColorRatioB()
                || ratioType == 3 && randomHelper.next(1000) < config.getSameColorRatioA()) {
            return lastColor;
        }
        // 再判断宝箱
        if (randomHelper.next(1000) < config.getBoxRatio()) {
            return -1;
        }
        // 剩下的随机
        int tmpColor = randomHelper.next(TOTAL_COLOR_COUNT - 1) + 1;
        return tmpColor == lastColor ? TOTAL_COLOR_COUNT : tmpColor;
    }

}
